<?php

namespace App\Kuafu\Shop\Model;

use App\Kuafu\Base\Model\BaseModel;
use App\Kuafu\Base\Model\Traits\KfSoftDeletes;
use App\Kuafu\Base\Model\Traits\KfUid;
use App\Kuafu\Pay\Model\PayStreamModel;
use App\Kuafu\Pay\Model\ShopPaymentModel;
use App\Kuafu\Shop\Enum\CodeEnum;
use App\Kuafu\Shop\Enum\ShopCodeEnum;
use App\Kuafu\Shop\Exceptions\ShopException;
use App\Kuafu\User\Model\Role;
use App\Kuafu\User\Model\User;
use App\Kuafu\User\Model\UserRoleMapping;
use App\Kuafu\WaiMai\Enum\WaiMaiDBEnum;
use App\Kuafu\WaiMai\Model\WaiMaiShopMappingModel;
use App\Scope\ShopScope;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Support\Facades\Redis;

class Shop extends BaseModel
{
    use HasFactory, KfSoftDeletes, KfUid;

    protected $connection   = 'mysql';
    protected $modelCached  = true;
    public    $incrementing = false;

    const DY_COUPON_VERIFY_SWITCH_ON   = 1;
    const DY_COUPON_VERIFY_SWITCH_OFF  = 0;
    const DY_COUPON_VERIFY_SWITCH_TEXT = [
        self::DY_COUPON_VERIFY_SWITCH_ON  => "开启",
        self::DY_COUPON_VERIFY_SWITCH_OFF => "关闭"
    ];

    const INTRODUCER_1    = 1;
    const INTRODUCER_2    = 2;
    const INTRODUCER_TEXT = [
        self::INTRODUCER_1 => [
            "title" => "引导顾客自拣串:",
            "desc"  => "将通过弹窗告知客户需自主拿框取串。"
        ],
        self::INTRODUCER_2 => [
            "title" => "常规:",
            "desc"  => "不会提醒顾客拿框自取串,默认顾客下单后店员会代拣串并烹饪。"
        ]
    ];

    protected $fillable = [
        'name',
        'menuId',
        'shopCode',
        'shopMobile',
        'shopContact',
        'imageUrl',
        'type',
        'addressPrefix',
        'address',
        'startAt',
        'endAt',
        'brandId',
        'province',
        'city',
        'district',
        'lng',
        'lat',
        'branch',
        'privateDrainageImg',
        'orderingQrCode',
        'status',
        'formalUseAt',
        'id',
        'appletStatus',
        'cashRegisterStatus',
        'dyCouponVerifySwitch'
    ];

    public function getCreatedAtAttribute()
    {
        return date('Y-m-d H:i:s', $this->attributes['createdAt']);
    }

    public function getUpdatedAtAttribute()
    {
        return date('Y-m-d H:i:s', $this->attributes['updatedAt']);
    }

    public function getKfShopCodeAttribute()
    {
        return str_pad($this->shopCode, ShopCodeEnum::CODE_TEXT[ShopCodeEnum::LEADING_ZERO], "0", STR_PAD_LEFT);
    }

    public function createdByUidRel()
    {
        return $this->hasOne(User::class, 'id', 'createdByUid')->select('id', 'username');
    }

    public function updatedByUidRel()
    {
        return $this->hasOne(User::class, 'id', 'updatedByUid')->select(['id', 'username']);
    }

    public function shopArchivesRel()
    {
        return $this->hasOne(ShopArchives::class, 'shopId');
    }

    /**
     * @return HasOne
     */
    public function shopFuYouPaymentsRel(): HasOne
    {
        return $this->hasOne(ShopPaymentModel::class, 'shopId', 'id')
                    ->where('payChannel', PayStreamModel::PAY_CHANNEL_FY);
    }

    /**
     * 新增店铺
     * @param string $name
     * @param int $shopCode
     * @param string $shopMobile
     * @param int $type
     * @param string $addressPrefix
     * @param string $address
     * @param int $brandId
     * @param int $startAt
     * @param int $endAt
     * @param int $province
     * @param int $city
     * @param int $district
     * @param string $lng
     * @param string $lat
     * @param string $branch
     * @param string $privateDrainageImg
     * @param string $orderingQrCode
     * @param int $formalUseAt
     * @return Shop
     * @throws ShopException
     */
    public static function addData(
        string $name,
        int $shopCode,
        string $shopMobile,
        int $type,
        string $addressPrefix,
        string $address,
        int $brandId,
        int $startAt,
        int $endAt,
        int $province,
        int $city,
        int $district,
        string $lng,
        string $lat,
        string $branch,
        string $privateDrainageImg,
        string $orderingQrCode,
        int $formalUseAt = 0,
        int $status = CodeEnum::SHOP_STATUS_NORMAL
    ): Shop {
        try {
            $shopModel                     = new Shop();
            $shopModel->id                 = $shopModel->maxId();
            $shopModel->name               = $name;
            $shopModel->shopCode           = $shopCode;
            $shopModel->shopMobile         = $shopMobile;
            $shopModel->imageUrl           = '';
            $shopModel->type               = $type;
            $shopModel->addressPrefix      = $addressPrefix;
            $shopModel->address            = $address;
            $shopModel->startAt            = $startAt;
            $shopModel->endAt              = $endAt;
            $shopModel->brandId            = $brandId;
            $shopModel->province           = $province;
            $shopModel->city               = $city;
            $shopModel->district           = $district;
            $shopModel->lng                = $lng;
            $shopModel->lat                = $lat;
            $shopModel->branch             = $branch;
            $shopModel->privateDrainageImg = $privateDrainageImg;
            $shopModel->orderingQrCode     = $orderingQrCode;
            $shopModel->formalUseAt        = $formalUseAt;
            $shopModel->status             = $status;
            $shopModel->appletStatus       = CodeEnum::SHOP_APPLET_STATUS_SUSPEND;
            $shopModel->save();
            return $shopModel;
        } catch (\Exception $exception) {
            throw new ShopException(ShopCodeEnum::ERR_SHOP_INSERT, '', $exception);
        }
    }

    /**
     * 获取最大 id
     *
     * @return int
     */
    public function getMaxId(): int
    {
        $first = self::query()->select('id')->where('id', '<', 100000)->orderBy('id', 'desc')->first();
        return $first->id;
    }


    /**
     * 判断是否存在某个 ID
     *
     * @param int $maxId
     * @return bool
     */
    public function checkIdExist(int $maxId): bool
    {
        $count = self::query()->where('id', $maxId)->count();
        return (bool)$count;
    }


    /**
     * 批量设置menuIds
     * @param array $ids
     * @param int $productMenuId
     * @return int
     */
    public static function setProductMenuIds(array $ids, int $productMenuId): int
    {
        return self::query()->whereIn('id', $ids)->update(['menuId' => $productMenuId]);
    }


    /**
     * 通过menuId查店铺
     *
     * @param int $productMenuId
     * @return \Illuminate\Support\Collection
     */
    public static function getShopsByMenuId(int $productMenuId)
    {
        return self::query()
                   ->where('menuId', $productMenuId)
                   ->select(['id as shopId', 'name', 'shopCode'])
                   ->get();
    }

    // 查询绑定x菜单的店铺数量
    public static function countShopsByMenuId(int $menuId)
    {
        return self::query()->where('menuId', $menuId)->count();
    }

    public static function getShopListByBrandPage(
        $brandId,
        $pageSize,
        $pageNum,
        $status,
        $name,
        $field,
        string $dimCode = ''
    ) {
        return self::query()
                   ->with('createdByUidRel')
                   ->with('updatedByUidRel')
                   ->with('shopFuYouPaymentsRel')
                   ->with('waimaiShopMappings')
                   ->when(ShopScope::getShopIdsArr(), function ($query) {
                       $query->whereIn("id", ShopScope::getShopIdsArr());
                   })
                   ->when($dimCode, function ($query) use ($dimCode) {
                       switch ($dimCode) {
                           case is_numeric($dimCode):
                               $query->where('id', $dimCode)->orWhere('shopCode', $dimCode);
                               break;
                           case substr($dimCode, 0, 1) === 'D' :
                               $serialNumberList = explode(',', $dimCode);
                               array_walk($serialNumberList, function (&$item) {
                                   $item = trim($item);
                               });
                               $serialNumberList = array_unique($serialNumberList);
                               if (count($serialNumberList) > 100) {
                                   throw new ShopException(0, '序列号查询数量不能超过100个');
                               }
                               $query->whereIn('serialNumber', $serialNumberList);
                               break;
                           case substr($dimCode, 0, 3) === '000' :
                               $list = ShopPaymentModel::query()
                                                       ->select('shopId')
                                                       ->where('payChannel', PayStreamModel::PAY_CHANNEL_FY)
                                                       ->whereRaw("payConfig -> '$.mch_id' = '" . $dimCode . "'")
                                                       ->get()
                                                       ->pluck('shopId')
                                                       ->values();
                               $query->whereIn('id', $list);
                               break;
                           default:
                               $query->Where('name', 'like', '%' . $dimCode . '%')
                                     ->orWhere('shortName', 'like', '%' . $dimCode . '%');
                       }
                   })
                   ->when($brandId, function ($query) use ($brandId) {
                       $query->where('brandId', '=', $brandId);
                   })
                   ->when($name, function ($query) use ($name) {
                       $query->where('name', 'like', "%{$name}%");
                   })
                   ->when($status !== null, function ($query) use ($status) {
                       $query->where('status', (int)$status);
                   })
                   ->paginate($pageSize, $field, $pageName = 'page', $pageNum);
    }

    public function waimaiShopMappings(): Relation
    {
        return $this->hasMany(WaiMaiShopMappingModel::class, 'shopId', 'id');
    }

    /**
     * 门店与用户表关联
     * @return HasManyThrough
     */
    public function staffRel()
    {
        return $this->hasManyThrough(
            User::class,
            UserRoleMapping::class,
            'shopId',
            'id',
            'id',
            'userId');
    }

    /**
     * 门店与角色表关联
     * @return HasManyThrough
     */
    public function roleRel()
    {
        return $this->hasManyThrough(
            Role::class,
            UserRoleMapping::class,
            'shopId',
            'id',
            'id',
            'roleId');
    }

    //根据ID获取门店信息
    public static function getShopById($shopId)
    {
        return Shop::query()
                   ->where('id', $shopId)
                   ->first()
                   ->toArray();
    }

    /**
     * 获取正式使用时间门店列表
     *
     * @param int $time
     * @return Builder[]|Collection
     */
    public static function getUsefulShopLists(int $time = 0, array $field = ['id', 'name', 'shopCode', 'formalUseAt'])
    {
        return self::query()
                   ->where('status', CodeEnum::SHOP_STATUS_NORMAL)
                   ->where('formalUseAt', '>', 0)
                   ->when($time, function ($query) use ($time) {
                       $query->where('formalUseAt', '<', $time > 0 ? $time : time());
                   })
                   ->where('shopCode', '<', 9999)
//                   ->where('formalUseAt', '<', $time > 0 ? $time : time())
                   ->select($field)
                   ->get();
    }

    /**
     * 用于观远的门店列表
     *
     * @param int $time
     * @return Builder[]|Collection
     */
    public static function getGyShopList()
    {
        $field      = ['id', 'name', 'shopCode', 'formalUseAt'];
        $skipShopId = [];
        return self::query()
                   ->where('status', CodeEnum::SHOP_STATUS_NORMAL)
                   ->where('shopCode', '<', 8000) // 过滤测试门店 超出门店数量再说
                   ->select($field)
                   ->get();
    }

    public static function getShopByCode(int $shopCode, int $brandId)
    {
        return Shop::query()->where('shopCode', $shopCode)->where('brandId', $brandId)->first();
    }

    /**
     * 根据 Codes 获取门店列表
     *
     * @param int $shopCode
     * @param int $brandId
     * @return Builder|Model|object|null
     */
    public static function getShopByCodes(array $shopCode, int $brandId, array $field)
    {
        return Shop::query()
                   ->whereIn('shopCode', $shopCode)
                   ->where('brandId', $brandId)
                   ->when($field, function ($query) use ($field) {
                       $query->select($field);
                   })
                   ->get();
    }

    /**
     * 根据 Ids 获取门店列表
     *
     * @param int $shopCode
     * @param int $brandId
     * @return Builder|Model|object|null
     */
    public static function getShopByIds(array $shopIds, int $brandId, array $field)
    {
        return Shop::query()
                   ->with('shopFuYouPaymentsRel')
                   ->whereIn('id', $shopIds)
                   ->where('brandId', $brandId)
                   ->when($field, function ($query) use ($field) {
                       $query->select($field);
                   })
                   ->get()
                   ->map(function ($item) {
                       $item['kfShopCode'] = $item->kfShopCode;
                       return $item;
                   });
    }

    /**
     * @param int $id
     * @return Builder|Model|object|null
     */
    public static function getShopDetailById(int $id)
    {
        return self::query()->where("id", $id)->first();
    }

    public function waimaiShopMappingFromDouyin(): Relation
    {
        return $this->hasOne(WaiMaiShopMappingModel::class, 'shopId', 'id')
                    ->where('sourceType', WaiMaiDBEnum::SOURCE_TYPE_DOUYIN_WM);
    }
}
